﻿using System;
using System.Collections.Concurrent;
using UnityEngine;

namespace Share
{
    /// <summary>
    /// 单例对象管理助手
    /// </summary>
    public class InstanceHelper : MonoBehaviour
    {
        private static readonly object _lock = new();
        private static readonly ConcurrentDictionary<Type, Component> _singletonCache = new();
        private static readonly GameObject globalSingleton;
        public static readonly string TagSingleton = "__SingletonGlobal__";
        private static bool isInit = false;
        static InstanceHelper()
        {
            globalSingleton = GameObject.Find(TagSingleton) ?? new GameObject(TagSingleton);
        }

        /// <summary>
        /// 获取单例根对象
        /// </summary>
        /// <returns>单例根对象</returns>
        public static GameObject GetSingletonRoot()
        {
            if (globalSingleton == null) throw new NullReferenceException("Singleton root is null");

            lock (_lock)
            {
                if (Application.isPlaying && !isInit)
                {
                    DontDestroyOnLoad(globalSingleton);
                    isInit = true;
                }
                return globalSingleton;
            }
        }

        /// <summary>
        /// 获取指定类型的单例组件
        /// </summary>
        /// <typeparam name="T">组件类型</typeparam>
        /// <returns>单例组件实例</returns>
        public static T Singleton<T>() where T : Component
        {
            if (_singletonCache.TryGetValue(typeof(T), out var component))
            {
                return (T)component;
            }

            lock (_lock)
            {
                if (_singletonCache.TryGetValue(typeof(T), out component))
                {
                    return (T)component;
                }

                XKLog.Log(typeof(T).ToString());
                var instance = GetSingletonRoot().GetOrAddComponent<T>();
                _singletonCache[typeof(T)] = instance;
                return instance;
            }
        }
    }
}
